﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
// add
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Globalization;



namespace FormBase
{
    public partial class FPGM0060 : Form
    {
        // todo: q1 結束程式後, 仍會殘留.exe在taskmanager中. q2 receive and send command 的範例
        TcpListener Listener1 = null;

        // GetTimeServer2
        private static Socket _serverSocket;
        private static readonly List<Socket> _clientSockets = new List<Socket>();
        private const int _BUFFER_SIZE = 2048;
        private const int _PORT = 100;
        private static readonly byte[] _buffer = new byte[_BUFFER_SIZE];
        public FPGM0060()
        {
            InitializeComponent();
        }

        private void btnGetTimeServer2_Click(object sender, EventArgs e)
        {
            Console.Title = "Server";
            SetupServer();
            Console.ReadLine(); // When we press enter close everything
            CloseAllSockets();
        }
        private void SetupServer()
        {
            Console.WriteLine("Setting up server...");
            _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _serverSocket.Bind(new IPEndPoint(IPAddress.Any, _PORT));
            _serverSocket.Listen(5);
            _serverSocket.BeginAccept(AcceptCallback, null);
            Console.WriteLine("Server setup complete");
        }
        /// <summary>
        /// Close all connected client (we do not need to shutdown the server socket as its connections
        /// are already closed with the clients)
        /// </summary>
        private static void CloseAllSockets()
        {
            foreach (Socket socket in _clientSockets)
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
            }
            _serverSocket.Close();
        }

        private static void AcceptCallback(IAsyncResult AR)
        {
            Socket socket;
            try
            {
                socket = _serverSocket.EndAccept(AR);
            }
            catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
            {
                return;
            }

            _clientSockets.Add(socket);
            socket.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);
            Console.WriteLine("Client connected, waiting for request...");
            _serverSocket.BeginAccept(AcceptCallback, null);
        }
        private static void ReceiveCallback(IAsyncResult AR)
        {
            Socket current = (Socket)AR.AsyncState;
            int received;

            try
            {
                received = current.EndReceive(AR);
            }
            catch (SocketException)
            {
                Console.WriteLine("Client forcefully disconnected");
                current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway
                _clientSockets.Remove(current);
                return;
            }

            byte[] recBuf = new byte[received];
            Array.Copy(_buffer, recBuf, received);
            string text = Encoding.ASCII.GetString(recBuf);
            Console.WriteLine("Received Text: " + text);

            if (text.ToLower() == "get time") // Client requested time
            {
                Console.WriteLine("Text is a get time request");
                byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
                current.Send(data);
                Console.WriteLine("Time sent to client");
            }
            else if (text.ToLower() == "exit") // Client wants to exit gracefully
            {
                // Always Shutdown before closing
                current.Shutdown(SocketShutdown.Both);
                current.Close();
                _clientSockets.Remove(current);
                Console.WriteLine("Client disconnected");
                return;
            }
            else
            {
                Console.WriteLine("Text is an invalid request");
                byte[] data = Encoding.ASCII.GetBytes("Invalid request");
                current.Send(data);
                Console.WriteLine("Warning Sent");
            }

            current.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
        }

        private static void SendCallback(IAsyncResult AR)
        {
            Socket socket = (Socket) AR.AsyncState;
            socket.EndSend(AR);
        }

        private void myListenBlocking()
        {
            DateTime now;
            String strDateLine;
            Encoding ASCII = Encoding.ASCII;
            Socket socket1 = null;
            int iPort;

            try
            {
                if (int.TryParse(txtPort.Text, out iPort) == false)
                {
                    CProject.mApp.PopupError("Wrong port");
                    return;
                }
                TcpListener tcpl = new TcpListener(IPAddress.Any, iPort); // listen on port 13
                tcpl.Start();
                while (true)
                {
                // ref async: http://stackoverflow.com/questions/2740664/1-second-tcplistener-pending-accepttcpclient-lag

                    // ??? Accept will block until someone connects
                    socket1 = tcpl.AcceptSocket();
                    now = DateTime.Now;
                    strDateLine = now.ToShortDateString() + " " + now.ToLongTimeString();
                    strDateLine = now.ToString("yyyy.MM.dd HH:mm:ss.fff");
                    Byte[] byteDateLine = ASCII.GetBytes(strDateLine.ToCharArray());
                    socket1.Send(byteDateLine, byteDateLine.Length, 0);
                    CProject.ShowMsg(string.Format("Sent {0}", strDateLine)); // ??? 不會顯示
                }
            }
            catch (SocketException socketError)
            {
                if (socketError.ErrorCode == 10048)
                    CProject.ShowMsgError(string.Format("Connection to this port failed.  There is another server is listening on this port."));
            }
            finally
            {
                if (socket1 != null)
                    socket1.Close();
            }
 
        }
        private void myListenNonBlocking()
        {
            DateTime now;
            String strDateLine;
            Encoding ASCII = Encoding.ASCII;
            //Socket socket1 = null;
            int iPort;

            try
            {


                if (int.TryParse(txtPort.Text, out iPort) == false)
                {
                    CProject.mApp.PopupError("Wrong port");
                    return;
                }
                Listener1 = new TcpListener(IPAddress.Any, iPort); // listen on port 13
                Listener1.Start();
                Listener1.BeginAcceptSocket(myAcceptConnection, null);
                while (chkListen.Checked && Listener1.Server.IsBound)
                {
                    Thread.Sleep(500);
                    Application.DoEvents();
                }

                //tcpl.Start();
                // tcpl.BeginAcceptSocket(
                // ref: http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(SYSTEM.NET.SOCKETS.TCPLISTENER.BEGINACCEPTSOCKET);k(BEGINACCEPTSOCKET);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV3.5%22);k(DevLang-CSHARP)&rd=true 
                // ref: http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(SYSTEM.NET.SOCKETS.TCPLISTENER.BEGINACCEPTSOCKET);k(BEGINACCEPTSOCKET);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV3.5%22);k(DevLang-CSHARP)&rd=true
                // ref: http://stackoverflow.com/questions/2766463/c-sharp-accepting-sockets-in-async-fasion-best-practices
                //Listener1.Start();
                //Listener1.BeginAcceptSocket(myAcceptConnection, null);
                //while (Listener1.Server.IsBound)
                //{
                //    CProject.gSleep(500);
                //}

            }
            catch (SocketException socketError)
            {
                if (socketError.ErrorCode == 10048)
                    CProject.ShowMsgError(string.Format("Connection to this port failed.  There is another server is listening on this port."));
            }
            finally
            {
                //if (socket1 != null)
                //    socket1.Close();
            }

        }
        private void myAcceptConnection(IAsyncResult ar)
        {
            Socket socket1 = Listener1.EndAcceptSocket(ar);
            //Encoding ASCII = Encoding.ASCII;
            Listener1.BeginAcceptSocket(myAcceptConnection, null); // accepting next socket

            // Receive data.
            //int iMaxReceive = socket1.ReceiveBufferSize;
            //byte[] baMaxReceive = new byte[iMaxReceive];
            //int iRecieve = socket1.Receive(baMaxReceive);
            //byte[] baReceive = new byte[iRecieve];
            //for (int i = 0; i < iRecieve; i++)
            //    baReceive[i] = baMaxReceive[i];

            string sDateLine = DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss.fff");
            Byte[] byteDateLine = Encoding.ASCII.GetBytes(sDateLine.ToCharArray());
            socket1.Send(byteDateLine, byteDateLine.Length, 0);
            //CProject.ShowMsg(string.Format("Sent {0}", sDateLine)); // ??? 不會顯示
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            myListenBlocking();
        }

        private void btnDefaultRS232_Click(object sender, EventArgs e)
        {
            myDefaultValues();
        }

        private void myDefaultValues()
        {
            txtPort.Text = "8013";
            chkListen.Checked = true;
        }

        private void FPGM0060_Load(object sender, EventArgs e)
        {
            Text = "TCP Server template";

            myClear();

            myDefaultValues();

        }
        private void myClear()
        {
            txtBarcode.Clear();
            txtMsg.Clear();
            txtHex.Clear();
            txtLength.Clear();
            chkListen.Checked = false;
            ActiveControl = txtBarcode;
        }

        private void ListenNonBlocking_Click(object sender, EventArgs e)
        {
            myListenNonBlocking();
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            long l1 = 0;
            if (long.TryParse(txtLong.Text, out l1))
                txtMsg.Text = CCommon.gGetPhysicalFilename(l1);
            else
                txtMsg.Text = "Please input long no.";
        }

        private void btnNonBlocking2_Click(object sender, EventArgs e)
        {
            myListenNonBlocking2();
        }
        private void myListenNonBlocking2()
        {
            //DateTime now;
            //String strDateLine;
            //Encoding ASCII = Encoding.ASCII;
            //Socket socket1 = null;
            //int iPort;

            //try
            //{


            //    if (int.TryParse(txtPort.Text, out iPort) == false)
            //    {
            //        CProject.PopupError("Wrong port");
            //        return;
            //    }
            //    Listener1 = new TcpListener(IPAddress.Any, iPort); // listen on port 13
            //    Listener1.Start();
            //    Listener1.BeginAcceptSocket(myAcceptConnection, null);
            //    while (chkListen.Checked && Listener1.Server.IsBound)
            //    {
            //        //acceptedSocketEvent.Reset();  
            //        Thread.Sleep(500);
            //        Application.DoEvents();
            //    }

            //    //tcpl.Start();
            //    // tcpl.BeginAcceptSocket(
            //    // ref: http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(SYSTEM.NET.SOCKETS.TCPLISTENER.BEGINACCEPTSOCKET);k(BEGINACCEPTSOCKET);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV3.5%22);k(DevLang-CSHARP)&rd=true 
            //    // ref: http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(SYSTEM.NET.SOCKETS.TCPLISTENER.BEGINACCEPTSOCKET);k(BEGINACCEPTSOCKET);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV3.5%22);k(DevLang-CSHARP)&rd=true
            //    // ref: http://stackoverflow.com/questions/2766463/c-sharp-accepting-sockets-in-async-fasion-best-practices
            //    //Listener1.Start();
            //    //Listener1.BeginAcceptSocket(myAcceptConnection, null);
            //    //while (Listener1.Server.IsBound)
            //    //{
            //    //    CProject.gSleep(500);
            //    //}

            //}
            //catch (SocketException socketError)
            //{
            //    if (socketError.ErrorCode == 10048)
            //        CProject.ShowMsgError(string.Format("Connection to this port failed.  There is another server is listening on this port."));
            //}
            //finally
            //{
            //    if (socket1 != null)
            //        socket1.Close();
            //}

        }

        private void FPGM0060_FormClosing(object sender, FormClosingEventArgs e)
        {
            Listener1.Stop();
        }


    }
}
